package com.actionpals.components.controls
{
	import com.actionpals.components.core.UITextComponent;
	import com.actionpals.enum.InvalidationType;
	import com.actionpals.enum.MouseState;
	import com.actionpals.events.ComponentEvent;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.ui.Keyboard;
	import flash.utils.Timer;
	
	public class BaseButton extends UITextComponent
	{
		protected var _background:DisplayObject;
		protected var _upState:DisplayObject;
		protected var _overState:DisplayObject;
		protected var _downState:DisplayObject;
		protected var _disabledState:DisplayObject;
		protected var _selectedUpState:DisplayObject;
		protected var _selectedOverState:DisplayObject;
		protected var _selectedDownState:DisplayObject;
		protected var _selectedDisabledState:DisplayObject;
		protected var _mouseState:String;
		protected var _oldMouseState:String;
		protected var _mouseStateLocked:Boolean = false;
		protected var _unlockedMouseState:String;
		protected var _selected:Boolean = false;
		protected var _toggle:Boolean = false;
		protected var _autoRepeat:Boolean = false;
		protected var _repeatDelay:Number = 500;
		protected var _repeatInterval:Number = 35;
		protected var _pressTimer:Timer;
		
		public function BaseButton()
		{
			super();
			
			buttonMode = true;
			mouseChildren = false;
			useHandCursor = false;
			
			setupMouseEvents();
			setMouseState( MouseState.UP );
			
			_pressTimer = new Timer( 1, 0 );
			_pressTimer.addEventListener( TimerEvent.TIMER, buttonDown, false, 0, true );
		}
		
		public override function get enabled():Boolean
		{
			return super.enabled;
		}
		public override function set enabled( value:Boolean ):void
		{
			super.enabled = value;
			mouseEnabled = value;
		}
		
		public function get upState():DisplayObject
		{
			if( _upState ) return _upState;
			_upState = new Sprite();
			Sprite( _upState ).graphics.beginFill( 0, 0 );
			Sprite( _upState ).graphics.drawRect( 0, 0, width, height );
			Sprite( _upState ).graphics.endFill();
			return _upState;
		}
		public function set upState( value:DisplayObject ):void
		{
			_upState = value;
			if( !width )
			{
				_startWidth = _upState.width;
				_width = _upState.width;
			}
			if( !height )
			{
				_startHeight = _upState.height;
				_height = _upState.height;
			}
		}
		
		public function get overState():DisplayObject
		{
			return _overState ? _overState : upState;
		}
		public function set overState( value:DisplayObject ):void
		{
			_overState = value;
		}
		
		public function get downState():DisplayObject
		{
			return _downState ? _downState : overState;
		}
		public function set downState( value:DisplayObject ):void
		{
			_downState = value;
		}
		
		public function get disabledState():DisplayObject
		{
			return _disabledState ? _disabledState : upState;
		}
		public function set disabledState( value:DisplayObject ):void
		{
			_disabledState = value;
		}
		
		public function get selectedUpState():DisplayObject
		{
			return _selectedUpState ? _selectedUpState : upState;
		}
		public function set selectedUpState( value:DisplayObject ):void
		{
			_selectedUpState = value;
		}
		
		public function get selectedOverState():DisplayObject
		{
			return _selectedOverState ? _selectedOverState : overState;
		}
		public function set selectedOverState( value:DisplayObject ):void
		{
			_selectedOverState = value;
		}
		
		public function get selectedDownState():DisplayObject
		{
			return _selectedDownState ? _selectedDownState : downState;
		}
		public function set selectedDownState( value:DisplayObject ):void
		{
			_selectedDownState = value;
		}
		
		public function get selectedDisabledState():DisplayObject
		{
			return _selectedDisabledState ? _selectedDisabledState : disabledState;
		}
		public function set selectedDisabledState( value:DisplayObject ):void
		{
			_selectedDisabledState = value;
		}
		
		public function get selected():Boolean
		{
			return _toggle ? _selected : false;
		}
		public function set selected( value:Boolean ):void
		{
			if( _selected == value ) { return; }
			_selected = value;
			if( _toggle )
			{
				invalidate( InvalidationType.STATE );
			}
		}
		
		public function get autoRepeat():Boolean
		{
			return _autoRepeat;
		}
		public function set autoRepeat( value:Boolean ):void
		{
			_autoRepeat = value;
		}
		
		public function set mouseStateLocked( value:Boolean ):void
		{
			_mouseStateLocked = value;
			if( value == false ) { setMouseState( _unlockedMouseState ); }
			else { _unlockedMouseState = _mouseState; }
		}
		
		public function setMouseState(state:String):void
		{
			if( _mouseStateLocked ) { _unlockedMouseState = state; return; }
			if( _mouseState == state ) { return; }
			_mouseState = state;
			invalidate( InvalidationType.STATE );
		}
		
		public function get repeatDelay():Number
		{
			return _repeatDelay;
		}
		public function set repeatDelay( value:Number ):void
		{
			_repeatDelay = value;
		}
		
		public function get repeatInterval():Number
		{
			return _repeatInterval;
		}
		public function set repeatInterval( value:Number ):void
		{
			_repeatInterval = value;
		}
		
		public function get toggle():Boolean
		{
			return _toggle;
		}
		public function set toggle( value:Boolean ):void
		{
			if( !value && selected ) { selected = false; }
			_toggle = value;
			if( _toggle ) { addEventListener( MouseEvent.CLICK, toggleSelected, false, 0, true); }
			else { removeEventListener( MouseEvent.CLICK, toggleSelected ); }
		}
		
		protected function toggleSelected( event:MouseEvent ):void
		{
			selected = !selected;
			dispatchEvent( new Event( Event.CHANGE, true ) );
		}
		
		protected function setupMouseEvents():void
		{
			addEventListener( MouseEvent.ROLL_OVER, mouseEventHandler, false, 0, true );
			addEventListener( MouseEvent.MOUSE_DOWN, mouseEventHandler, false, 0, true );
			addEventListener( MouseEvent.MOUSE_UP, mouseEventHandler, false, 0, true );
			addEventListener( MouseEvent.ROLL_OUT, mouseEventHandler, false, 0, true );
		}
		
		protected function mouseEventHandler( evt:MouseEvent ):void
		{
			if( evt.type == MouseEvent.MOUSE_DOWN )
			{
				setMouseState( MouseState.DOWN );
				startPress();
			}
			else if( evt.type == MouseEvent.ROLL_OVER || evt.type == MouseEvent.MOUSE_UP )
			{
				setMouseState( MouseState.OVER );
				endPress();
			}
			else if( evt.type == MouseEvent.ROLL_OUT )
			{
				setMouseState( MouseState.UP );
				endPress();
			}
		}
		
		protected function startPress():void
		{
			if( _autoRepeat )
			{
				_pressTimer.delay = repeatDelay;
				_pressTimer.start();
			}
			dispatchEvent( new ComponentEvent( ComponentEvent.BUTTON_DOWN, true ) );
		}
		
		protected function buttonDown( evt:TimerEvent ):void
		{
			if( !_autoRepeat ) { endPress(); return; }
			if( _pressTimer.currentCount == 1 ) { _pressTimer.delay = repeatInterval; }
			dispatchEvent( new ComponentEvent( ComponentEvent.BUTTON_DOWN, true ) );
		}
		
		protected function endPress():void
		{
			_pressTimer.reset();
		}
		
		protected override function draw():void
		{
			if( isInvalid( InvalidationType.STYLES, InvalidationType.STATE ) )
			{
				drawBackground();
				invalidate( InvalidationType.SIZE );
			}
			if( isInvalid( InvalidationType.SIZE ) )
			{
				drawLayout();
			}
			super.draw();
		}
		
		protected function drawBackground():void
		{
			var state:String = enabled ? _mouseState : "disabled";
			if( _selected ) { state = "selected" + state.substr( 0, 1 ).toUpperCase() + state.substr( 1 ); }
			state += "State";
			var bg:DisplayObject = _background;
			_background = this[ state ];
			if( !width )
			{
				_startWidth = _background.width;
				_width = _background.width;
			}
			if( !height )
			{
				_startHeight = _background.height;
				_height = _background.height;
			}
			addChildAt( _background, 0 );
			if( bg != null && bg != _background ) { removeChild( bg ); }
		}
		
		protected function drawLayout():void
		{
			_background.width = width;
			_background.height = height;
		}
		
		protected override function keyDownHandler( evt:KeyboardEvent ):void
		{
			if( !enabled ) { return; }
			if( evt.keyCode == Keyboard.SPACE )
			{
				if( _oldMouseState == null )
				{
					_oldMouseState = _mouseState;
				}
				setMouseState( MouseState.DOWN );
				startPress();
			}
		}
			
		protected override function keyUpHandler( evt:KeyboardEvent ):void
		{
			if( !enabled ) { return; }
			if( evt.keyCode == Keyboard.SPACE )
			{
				setMouseState( _oldMouseState );
				_oldMouseState = null;
				endPress();
				dispatchEvent( new MouseEvent( MouseEvent.CLICK ) );
			}
		}
		
	}
}